<template>
  <div
    class="upload"
    v-show="modelValue"
    :style="{ height: title.trim().length > 0 ? '458px' : '394px' }"
  >
    <div class="top-nav" v-show="title.trim().length > 0">
      <span class="tip">{{ title }}</span>
      <div class="close-btn" @click="off">
        <img src="./images/delete.png" alt="" />
      </div>
    </div>
    <div class="content">
      <div
        class="left-avatar"
        @touchstart="imgStartMove"
        @touchmove="imgMove"
        @mousedown="imgStartMove"
        @mousemove="imgMove"
      >
        <div class="avatar-container" @wheel.prevent="handleMouseWheel">
          <img
            :src="sourceImgUrl"
            v-show="sourceImgUrl"
            class="avatar-image"
            :style="sourceImgStyle"
            @drag="preventDefault"
            @dragstart="preventDefault"
            @dragend="preventDefault"
            @dragleave="preventDefault"
            @dragover="preventDefault"
            @dragenter="preventDefault"
            @drop="preventDefault"
            @touchstart="imgStartMove"
            @touchmove="imgMove"
            @touchend="createImg"
            @touchcancel="createImg"
            @mousedown="imgStartMove"
            @mousemove="imgMove"
            @mouseup="createImg"
            @mouseout="createImg"
            ref="img"
          />
        </div>
        <canvas
          v-show="false"
          :width="width"
          :height="height"
          ref="canvas"
        ></canvas>
        <div
          class="circle"
          :style="{ borderRadius: `${radius}%` }"
          @touchstart="imgStartMove"
          @touchmove="imgMove"
          @mousedown="imgStartMove"
          @mousemove="imgMove"
        ></div>
        <div class="tips">
          支持{{ supportFormatLists }} {{ supportFormatListsLength }}种格式
        </div>
      </div>
      <div class="right-preview">
        <span style="font-size: 16px; margin-bottom: 25px; user-select: none"
          >预览</span
        >
        <div class="big-preview">
          <div
            class="icon"
            :style="{ borderRadius: (radius / 100) * 96 + 'px' }"
            v-if="!createImgUrl"
          >
            SC
          </div>
          <img
            v-else
            class="icon"
            :src="createImgUrl"
            :style="previewBigStyle"
          />
          <span class="detail">96*96</span>
        </div>
        <div class="small-preview">
          <div
            class="icon"
            :style="{ borderRadius: (radius / 100) * 48 + 'px' }"
            v-if="!createImgUrl"
          >
            SC
          </div>
          <img
            v-else
            class="icon"
            :src="createImgUrl"
            :style="previewSmallStyle"
          />
          <span class="detail">48*48</span>
        </div>
      </div>
    </div>
    <div class="bottom-nav">
      <div class="icons">
        <div class="icon-container">
          <div @click="rotateImgReverse">
            <img src="./images/rotate-left.png" alt="" />
          </div>
          <div
            @mousedown="startZoomAdd"
            @mouseout="endZoomAdd"
            @mouseup="endZoomAdd"
          >
            <img src="./images/scale-add.png" alt="" />
          </div>
          <div
            @mousedown="startZoomSub"
            @mouseout="endZoomSub"
            @mouseup="endZoomSub"
          >
            <img src="./images/sacle-sub.png" alt="" />
          </div>
          <div @click="rotateImg">
            <img src="./images/rotate-right.png" alt="" />
          </div>
        </div>
      </div>
      <div class="btns">
        <div class="btn-item to-upload" v-show="true" @click="handleClick">
          上传
          <input
            type="file"
            accept="image/*"
            v-show="false"
            @change="handleChange"
            ref="fileinput"
          />
        </div>
        <div class="btn-item confirm" @click="prepareUpload">确定</div>
      </div>
    </div>
  </div>
</template>

<script>
import { defineComponent } from 'vue';
import language from 'vue-image-crop-upload/utils/language.js';
import mimes from 'vue-image-crop-upload/utils/mimes.js';
import data2blob from 'vue-image-crop-upload/utils/data2blob.js';
import effectRipple from 'vue-image-crop-upload/utils/effectRipple.js';

export default defineComponent({
  name: '',
  props: {
    title: {
      type: String,
      default: '',
    },
    icon: {
      type: Boolean,
    },
    supportFormat: {
      type: Array,
      default() {
        return ['png', 'svg'];
      },
    },
    radius: {
      type: Number,
      default: 50,
    },
    // 域，上传文件name，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
    field: {
      type: String,
      default: 'avatar',
    },
    // 原名key，类似于id，触发事件会带上（如果一个页面多个图片上传控件，可以做区分
    ki: {
      type: String,
      default: '0',
    },
    // 显示该控件与否
    modelValue: {
      type: Boolean,
      default: true,
    },
    // 上传地址
    url: {
      type: String,
      default: '',
    },
    // 其他要上传文件附带的数据，对象格式
    params: {
      type: Object,
      default: () => null,
    },
    //Add custom headers
    headers: {
      type: Object,
      default: () => null,
    },
    // 剪裁图片的宽
    width: {
      type: Number,
      default: 200,
    },
    // 剪裁图片的高
    height: {
      type: Number,
      default: 200,
    },
    // 不显示旋转功能
    noRotate: {
      type: Boolean,
      default: true,
    },
    // 不预览圆形图片
    noCircle: {
      type: Boolean,
      default: false,
    },
    // 不预览方形图片
    noSquare: {
      type: Boolean,
      default: false,
    },
    // 单文件大小限制 只支持10M以内的图片
    maxSize: {
      type: Number,
      default: 10240,
    },
    // 语言类型
    langType: {
      type: String,
      default: 'zh',
    },
    // 语言包
    langExt: {
      type: Object,
      default: () => null,
    },
    // 图片上传格式
    imgFormat: {
      type: String,
      default: 'png',
    },
    // 图片背景 jpg情况下生效
    imgBgc: {
      type: String,
      default: '#fff',
    },
    // 是否支持跨域
    withCredentials: {
      type: Boolean,
      default: false,
    },
    method: {
      type: String,
      default: 'POST',
    },
    initialImgUrl: {
      type: String,
      default: '',
    },
    allowImgFormat: {
      type: Array,
      default: () => ['png', 'svg'],
    },
  },

  data() {
    let that = this,
      { imgFormat, allowImgFormat, langType, langExt, width, height } = that,
      isSupported = true,
      tempImgFormat =
        allowImgFormat.indexOf(imgFormat) === -1 ? 'png' : imgFormat,
      lang = language[langType] ? language[langType] : language['en'],
      mime = mimes[tempImgFormat];
    // 规范图片格式
    // that.imgFormat = tempImgFormat;

    if (langExt) {
      Object.assign(lang, langExt);
    }
    if (typeof FormData != 'function') {
      isSupported = false;
    }
    return {
      // 图片的mime
      mime,

      // 语言包
      lang,

      // 浏览器是否支持该控件
      isSupported,
      // 浏览器是否支持触屏事件
      isSupportTouch: document.hasOwnProperty('ontouchstart'),

      // 步骤
      step: 1, //1选择文件 2剪裁 3上传

      // 上传状态及进度
      loading: 0, //0未开始 1正在 2成功 3错误
      progress: 0,

      // 是否有错误及错误信息
      hasError: false,
      errorMsg: '',

      // 需求图宽高比
      ratio: width / height,

      // 原图地址、生成图片地址
      sourceImg: null,
      sourceImgUrl: this.initialImgUrl,
      createImgUrl: this.initialImgUrl,

      // 原图片拖动事件初始值
      sourceImgMouseDown: {
        on: false,
        mX: 0, //鼠标按下的坐标
        mY: 0,
        x: 0, //scale原图坐标
        y: 0,
      },

      // 生成图片预览的容器大小
      previewContainer: {
        width: 96,
        height: 96,
      },

      // 原图容器宽高
      sourceImgContainer: {
        // sic

        width: 210,
        height: 211, // 如果生成图比例与此一致会出现bug，先改成特殊的格式吧，哈哈哈
      },

      // 原图展示属性
      scale: {
        zoomAddOn: false, //按钮缩放事件开启
        zoomSubOn: false, //按钮缩放事件开启
        range: 1, //最大100

        x: 0,
        y: 0,
        width: 210,
        height: 210,
        maxWidth: 0,
        maxHeight: 0,
        minWidth: 0, //最宽
        minHeight: 0,
        naturalWidth: 0, //原宽
        naturalHeight: 0,
      },
    };
  },

  computed: {
    // 支持的图片格式的string 例：PNG、SVG
    supportFormatLists() {
      return this.supportFormat.map(item => item.toUpperCase()).join('、');
    },
    // 支持的图片类型的种类的个数
    supportFormatListsLength() {
      return this.supportFormat.length;
    },
    // 支持的Mime的类型 【’image/png‘,'image/svg+xml】 mimes.js中定义的文件类型
    supportMimeTypes() {
      const mimeLists = [];
      Object.keys(mimes).forEach(key => {
        this.supportFormat.forEach(support => {
          support === key && mimeLists.push(mimes[key]);
        });
      });
      return mimeLists;
    },
    // 进度条样式
    progressStyle() {
      let { progress } = this;
      return {
        width: progress + '%',
      };
    },
    // 原图样式
    sourceImgStyle() {
      let { scale, sourceImgMasking } = this,
        top = scale.y + sourceImgMasking.y + 'px',
        left = scale.x + sourceImgMasking.x + 'px';
      return {
        top,
        left,
        'user-select': 'none',
        width: scale.width + 'px',
        height: scale.height + 'px', // 兼容 Opera
      };
    },
    // 原图蒙版属性
    sourceImgMasking() {
      let { width, height, ratio, sourceImgContainer } = this,
        sic = sourceImgContainer,
        sicRatio = sic.width / sic.height, // 原图容器宽高比
        x = 0,
        y = 0,
        w = sic.width,
        h = sic.height,
        scale = 1;
      if (ratio < sicRatio) {
        scale = sic.height / height;
        w = sic.height * ratio;
        x = (sic.width - w) / 2;
      }
      if (ratio > sicRatio) {
        scale = sic.width / width;
        h = sic.width / ratio;
        y = (sic.height - h) / 2;
      }
      return {
        scale, // 蒙版相对需求宽高的缩放
        x,
        y,
        width: w,
        height: h,
      };
    },
    // 原图遮罩样式
    sourceImgShadeStyle() {
      let { sourceImgMasking, sourceImgContainer } = this,
        sic = sourceImgContainer,
        sim = sourceImgMasking,
        w = sim.width == sic.width ? sim.width : (sic.width - sim.width) / 2,
        h =
          sim.height == sic.height ? sim.height : (sic.height - sim.height) / 2;
      return {
        width: w + 'px',
        height: h + 'px',
      };
    },
    previewBigStyle() {
      let { width, height, ratio, previewContainer } = this,
        pc = previewContainer,
        w = pc.width,
        h = pc.height,
        pcRatio = w / h;
      if (ratio < pcRatio) {
        w = pc.height * ratio;
      }
      if (ratio > pcRatio) {
        h = pc.width / ratio;
      }
      return {
        width: w + 'px',
        height: h + 'px',
        'border-radius': w * (this.radius / 100) + 'px',
      };
    },
    previewSmallStyle() {
      let { width, height, ratio, previewContainer } = this,
        pc = previewContainer,
        w = pc.width - 48,
        h = pc.height - 48,
        pcRatio = w / h;
      if (ratio < pcRatio) {
        w = pc.height * ratio;
      }
      if (ratio > pcRatio) {
        h = pc.width / ratio;
      }
      return {
        width: w + 'px',
        height: h + 'px',
        'border-radius': w * (this.radius / 100) + 'px',
      };
    },
  },

  watch: {
    modelValue(newValue) {
      if (newValue && this.loading != 1) {
        this.reset();
      }
    },
  },
  created() {
    // 绑定按键esc隐藏此插件事件
    document.addEventListener('keyup', this.handleEscClose);
  },

  beforeUnmount() {
    document.removeEventListener('keyup', this.handleEscClose);
  },

  mounted() {
    if (this.sourceImgUrl) {
      this.startCrop();
    }
  },
  methods: {
    handleEscClose(e) {
      if (this.modelValue && (e.key == 'Escape' || e.keyCode == 27)) {
        this.off();
      }
    },
    // 点击波纹效果
    ripple(e) {
      effectRipple(e);
    },
    // 关闭控件
    off() {
      setTimeout(() => {
        this.$emit('update:modelValue', false);
        if (this.step == 3 && this.loading == 2) {
          this.setStep(1);
        }
      }, 200);
    },
    // 设置步骤
    setStep(no) {
      // 延时是为了显示动画效果呢，哈哈哈
      setTimeout(() => {
        this.step = no;
      }, 200);
    },

    /* 图片选择区域函数绑定
		 ---------------------------------------------------------------*/
    preventDefault(e) {
      e.preventDefault();
      return false;
    },
    handleClick(e) {
      if (this.loading !== 1) {
        if (e.target !== this.$refs.fileinput) {
          e.preventDefault();
          if (document.activeElement !== this.$refs) {
            this.$refs.fileinput.click();
          }
        }
      }
    },
    handleChange(e) {
      e.preventDefault();
      if (this.loading !== 1) {
        let files = e.target.files || e.dataTransfer.files;
        const isValidFormat = this.supportMimeTypes.includes(
          files[0] && files[0].type
        );
        if (!files[0]) {
          console.log('您取消了上传图片的操作！');
          return;
        }
        if (!isValidFormat) {
          console.log('请上传满足要求的图片格式！');
          return;
        }
        this.reset();
        if (this.checkFile(files[0])) {
        }
      }
    },
    /* ---------------------------------------------------------------*/

    // 检测选择的文件是否合适
    checkFile(file) {
      let that = this,
        { lang, maxSize } = that;
      // 仅限图片
      if (file?.type.indexOf('image') === -1) {
        that.hasError = true;
        that.errorMsg = lang.error.onlyImg;
        return false;
      }

      // 超出大小
      if (file?.size / 1024 > maxSize) {
        that.hasError = true;
        that.errorMsg = lang.error.outOfSize + maxSize + 'kb';
        return false;
      }
      return true;
    },
    // 重置控件
    reset() {
      let that = this;
      that.loading = 0;
      that.hasError = false;
      that.errorMsg = '';
      that.progress = 0;
    },
    // 设置图片源
    setSourceImg(file) {
      // 解决点击上传按钮后没有选择文件取消操作的报错
      if (file) {
        this.$emit('src-file-set', file.name, file.type, file.size);
        let that = this,
          fr = new FileReader();
        fr.onload = function (e) {
          // 设置图片源
          that.sourceImgUrl = fr.result;
          that.startCrop();
        };
        fr.readAsDataURL(file);
      }
    },
    // 剪裁前准备工作
    startCrop() {
      let that = this,
        { width, height, ratio, scale, sourceImgUrl, sourceImgMasking, lang } =
          that,
        sim = sourceImgMasking,
        img = new Image();
      img.src = sourceImgUrl;
      img.onload = function () {
        let nWidth = img.naturalWidth,
          nHeight = img.naturalHeight,
          nRatio = nWidth / nHeight,
          w = sim.width,
          h = sim.height,
          x = 0,
          y = 0;
        // 图片像素不达标
        // if (nWidth < width || nHeight < height) {
        //   that.hasError = true;
        //   that.errorMsg = lang.error.lowestPx + width + '*' + height;
        //   return false;
        // }
        if (ratio > nRatio) {
          h = w / nRatio;
          y = (sim.height - h) / 2;
        }
        if (ratio < nRatio) {
          w = h * nRatio;
          x = (sim.width - w) / 2;
        }
        scale.range = 0;
        scale.x = x;
        scale.y = y;
        scale.width = w;
        scale.height = h;
        scale.minWidth = w;
        scale.minHeight = h;
        scale.maxWidth = nWidth * sim.scale;
        scale.maxHeight = nHeight * sim.scale;
        scale.naturalWidth = nWidth;
        scale.naturalHeight = nHeight;
        that.sourceImg = img;
        that.createImg();
        that.setStep(2);
      };
    },
    // 鼠标按下图片准备移动
    imgStartMove(e) {
      e.preventDefault();
      // 支持触摸事件，则鼠标事件无效
      if (this.isSupportTouch && !e.targetTouches) {
        return false;
      }
      let et = e.targetTouches ? e.targetTouches[0] : e,
        { sourceImgMouseDown, scale } = this,
        simd = sourceImgMouseDown;
      simd.mX = et.screenX;
      simd.mY = et.screenY;
      simd.x = scale.x;
      simd.y = scale.y;
      simd.on = true;
    },
    // 鼠标按下状态下移动，图片移动
    imgMove(e) {
      e.preventDefault();
      // 支持触摸事件，则鼠标事件无效
      if (this.isSupportTouch && !e.targetTouches) {
        return false;
      }
      let et = e.targetTouches ? e.targetTouches[0] : e,
        {
          sourceImgMouseDown: { on, mX, mY, x, y },
          scale,
          sourceImgMasking,
        } = this,
        sim = sourceImgMasking,
        nX = et.screenX,
        nY = et.screenY,
        dX = nX - mX,
        dY = nY - mY,
        rX = x + dX,
        rY = y + dY;
      if (!on) return;
      if (rX > 0) {
        rX = 0;
      }
      if (rY > 0) {
        rY = 0;
      }
      if (rX < sim.width - scale.width) {
        rX = sim.width - scale.width;
      }
      if (rY < sim.height - scale.height) {
        rY = sim.height - scale.height;
      }
      scale.x = rX;
      scale.y = rY;
    },
    // 顺时针旋转图片
    rotateImg(e) {
      let {
          sourceImg,
          scale: { naturalWidth, naturalHeight },
        } = this,
        width = naturalHeight,
        height = naturalWidth,
        canvas = this.$refs.canvas,
        ctx = canvas.getContext('2d');
      canvas.width = width;
      canvas.height = height;
      ctx.clearRect(0, 0, width, height);

      ctx.fillStyle = 'rgba(0,0,0,0)';
      ctx.fillRect(0, 0, width, height);

      ctx.translate(width, 0);
      ctx.rotate((Math.PI * 90) / 180);

      if (sourceImg) {
        ctx.drawImage(sourceImg, 0, 0, naturalWidth, naturalHeight);
        let imgUrl = canvas.toDataURL(mimes['png']);
        this.sourceImgUrl = imgUrl;
        this.startCrop();
      }
    },
    // 逆时针旋转图片
    rotateImgReverse(e) {
      let {
          sourceImg,
          scale: { naturalWidth, naturalHeight },
        } = this,
        width = naturalHeight,
        height = naturalWidth,
        canvas = this.$refs.canvas,
        ctx = canvas.getContext('2d');
      canvas.width = width;
      canvas.height = height;
      ctx.clearRect(0, 0, width, height);

      ctx.fillStyle = 'rgba(0,0,0,0)';
      ctx.fillRect(0, 0, width, height);

      ctx.translate(0, height);
      ctx.rotate(-(Math.PI * 90) / 180);

      if (sourceImg) {
        ctx.drawImage(sourceImg, 0, 0, naturalWidth, naturalHeight);
        let imgUrl = canvas.toDataURL(mimes['png']);

        this.sourceImgUrl = imgUrl;
        this.startCrop();
      }
    },
    handleMouseWheel(e) {
      e = e || window.event;
      let { scale } = this;
      if (e.wheelDelta) {
        //判断浏览器IE，谷歌滑轮事件
        if (e.wheelDelta > 0) {
          //当滑轮向上滚动时
          this.zoomImg(scale.range >= 100 ? 100 : ++scale.range);
        }
        if (e.wheelDelta < 0) {
          this.zoomImg(scale.range <= 0 ? 0 : --scale.range);
        }
      } else if (e.detail) {
        //Firefox滑轮事件
        if (e.detail > 0) {
          //当滑轮向上滚动时
          this.zoomImg(scale.range >= 100 ? 100 : ++scale.range);
        }
        if (e.detail < 0) {
          this.zoomImg(scale.range <= 0 ? 0 : --scale.range);
        }
      }
    },
    // 按钮按下开始放大
    startZoomAdd(e) {
      let that = this,
        { scale } = that;
      scale.zoomAddOn = true;

      function zoom() {
        if (scale.zoomAddOn) {
          let range = scale.range >= 100 ? 100 : ++scale.range;
          that.zoomImg(range);
          setTimeout(function () {
            zoom();
          }, 60);
        }
      }
      zoom();
    },
    // 按钮松开或移开取消放大
    endZoomAdd(e) {
      this.scale.zoomAddOn = false;
    },
    // 按钮按下开始缩小
    startZoomSub(e) {
      let that = this,
        { scale } = that;
      scale.zoomSubOn = true;

      function zoom() {
        if (scale.zoomSubOn) {
          let range = scale.range <= 0 ? 0 : --scale.range;
          that.zoomImg(range);
          setTimeout(function () {
            zoom();
          }, 60);
        }
      }
      zoom();
    },
    // 按钮松开或移开取消缩小
    endZoomSub(e) {
      let { scale } = this;
      scale.zoomSubOn = false;
    },
    zoomChange(e) {
      this.zoomImg(e.target.value);
    },
    // 缩放原图
    zoomImg(newRange) {
      let that = this,
        { sourceImgMasking, sourceImgMouseDown, scale } = this,
        {
          maxWidth,
          maxHeight,
          minWidth,
          minHeight,
          width,
          height,
          x,
          y,
          range,
        } = scale,
        sim = sourceImgMasking,
        // 蒙版宽高
        sWidth = sim.width,
        sHeight = sim.height,
        // 新宽高
        nWidth = minWidth + (Math.abs(maxWidth - minWidth) * newRange) / 100,
        nHeight =
          minHeight + (Math.abs(maxHeight - minHeight) * newRange) / 100,
        // 新坐标（根据蒙版中心点缩放）
        nX = sWidth / 2 - (nWidth / width) * (sWidth / 2 - x),
        nY = sHeight / 2 - (nHeight / height) * (sHeight / 2 - y);
      // 判断新坐标是否超过蒙版限制
      if (nX > 0) {
        nX = 0;
      }
      if (nY > 0) {
        nY = 0;
      }
      if (nX < sWidth - nWidth) {
        nX = sWidth - nWidth;
      }
      if (nY < sHeight - nHeight) {
        nY = sHeight - nHeight;
      }

      // 赋值处理
      scale.x = nX;
      scale.y = nY;
      scale.width = nWidth;
      scale.height = nHeight;
      scale.range = newRange;
      setTimeout(function () {
        if (scale.range == newRange) {
          that.createImg();
        }
      }, 300);
    },
    // 生成需求图片
    createImg(e) {
      let that = this,
        {
          imgFormat,
          imgBgc,
          mime,
          sourceImg,
          scale: { x, y, width, height },
          sourceImgMasking: { scale },
        } = that,
        canvas = that.$refs.canvas,
        ctx = canvas.getContext('2d');
      if (e) {
        // 取消鼠标按下移动状态
        that.sourceImgMouseDown.on = false;
      }
      canvas.width = that.width;

      canvas.height = that.height;
      ctx.clearRect(0, 0, that.width, that.height);

      if (imgFormat == 'png') {
        ctx.fillStyle = 'rgba(0,0,0,0)';
      } else {
        // 如果jpg 为透明区域设置背景，默认白色
        ctx.fillStyle = imgBgc;
      }
      ctx.fillRect(0, 0, that.width, that.height);
      if (sourceImg) {
        ctx.drawImage(
          sourceImg,
          x / scale,
          y / scale,
          width / scale,
          height / scale
        );
        that.createImgUrl = canvas.toDataURL(mime);
      }
    },
    prepareUpload() {
      let { url, createImgUrl, field, ki } = this;
      this.$emit('crop-success', createImgUrl, field, ki);
      if (typeof url == 'string' && url) {
        this.upload();
      } else {
        this.off();
      }
    },
    // 上传图片
    upload() {
      let that = this,
        {
          lang,
          imgFormat,
          mime,
          url,
          params,
          headers,
          field,
          ki,
          createImgUrl,
          withCredentials,
          method,
        } = this,
        fmData = new FormData();
      console.log(imgFormat);
      // 添加其他参数
      if (typeof params == 'object' && params) {
        Object.keys(params).forEach(k => {
          fmData.append(k, params[k]);
        });
      }

      // 将field的添加放到表单域的最后，以支持阿里云OSS的表单上传
      fmData.append(
        field,
        data2blob(createImgUrl, mime),
        field + '.' + imgFormat
      );

      // 监听进度回调
      const uploadProgress = function (event) {
        if (event.lengthComputable) {
          that.progress = (100 * Math.round(event.loaded)) / event.total;
        }
      };

      // 上传文件
      that.reset();
      that.loading = 1;
      that.setStep(3);
      new Promise(function (resolve, reject) {
        let client = new XMLHttpRequest();
        client.open(method, url, true);
        client.withCredentials = withCredentials;
        client.onreadystatechange = function () {
          if (this.readyState !== 4) {
            return;
          }
          if (
            this.status === 200 ||
            this.status === 201 ||
            this.staus === 202
          ) {
            resolve(JSON.parse(this.responseText));
          } else {
            reject(this.status);
          }
        };
        client.upload.addEventListener('progress', uploadProgress, false); //监听进度
        // 设置header
        if (typeof headers == 'object' && headers) {
          Object.keys(headers).forEach(k => {
            client.setRequestHeader(k, headers[k]);
          });
        }
        client.send(fmData);
      }).then(
        // 上传成功
        function (resData) {
          if (that.modelValue) {
            that.loading = 2;
            that.$emit('crop-upload-success', resData, field, ki);
          }
        },
        // 上传失败
        function (sts) {
          if (that.modelValue) {
            that.loading = 3;
            that.hasError = true;
            that.errorMsg = lang.fail;
            that.$emit('crop-upload-fail', sts, field, ki);
          }
        }
      );
    },
  },
});
</script>

<style lang="less" scoped>
.upload {
  width: 607px;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid #eee;
  .top-nav {
    .tip {
      margin-left: 30px;
    }
    .close-btn {
      width: 18px;
      height: 18px;
      margin-right: 30px;
      cursor: pointer;
      img {
        width: 100%;
      }
    }
    font-size: 16px;
    font-family: PingFangSC-Regular, PingFang SC;
    font-weight: 400;
    width: 607px;
    height: 64px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid #cad6ee;
  }
  .content {
    width: 100%;
    height: 330px;
    display: flex;
    .left-avatar {
      cursor: move;
      margin-top: 24px;
      width: 308px;
      height: 282px;
      margin-left: 30px;
      position: relative;
      overflow: hidden;
      .avatar-container {
        position: relative;
        width: 370px;
        height: 370px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        .avatar-image {
          border: 80px solid transparent;
          position: absolute;
          user-select: none;
        }
      }
      .circle {
        // 解决被circle图层遮住不能进行scale操作的问题
        pointer-events: none;
        width: 210px;
        height: 210px;
        box-sizing: border-box;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        border: 1px solid #979797;
        box-shadow: 0 0 0 1000px rgb(0 0 0 / 50%);
        -webkit-box-shadow: 0 0 0 1000px rgb(0 0 0 / 50%);
      }
      .tips {
        text-align: center;
        user-select: none;
        color: #fff;
        font-size: 14px;
        line-height: 16px;
        height: 16px;
        position: absolute;
        left: 0;
        right: 0;
        margin: 0 auto;
        bottom: 10px;
      }
    }
    .right-preview {
      margin-top: 24px;
      width: 269px;
      height: 282px;
      display: flex;
      flex-direction: column;
      text-align: center;
      justify-content: flex-start;
      align-items: center;
      .detail {
        font-size: 14px;
        color: #7b8c9c;
        line-height: 20px;
        user-select: none;
      }
      .big-preview {
        display: flex;
        flex-direction: column;
        justify-content: center;
        .icon {
          width: 96px;
          height: 96px;
          border-radius: 50%;
          font-size: 50px;
          color: #fff;
          font-family: PingFangSC-Medium, PingFang SC;
          font-weight: 500;
          background-color: transparent;
          text-align: center;
          line-height: 100px;
          margin-bottom: 10px;
        }
        margin-bottom: 27px;
      }
      .small-preview {
        display: flex;
        flex-direction: column;
        justify-content: center;
        .icon {
          width: 48px;
          height: 48px;
          // border-radius: 50%;
          font-size: 24px;
          font-family: PingFangSC-Medium, PingFang SC;
          color: #fff;
          background-color: transparent;
          text-align: center;
          line-height: 50px;
          margin-bottom: 10px;
        }
      }
    }
  }
  .bottom-nav {
    width: 607px;
    height: 64px;
    background-color: #eff4f9;
    display: flex;
    align-items: flex-start;
    .icons {
      width: 338px;
      height: 24px;
      margin-top: 14px;
      .icon-container {
        width: 168px;
        height: 24px;
        margin: 0 auto;
        display: flex;
        justify-content: space-between;
        img {
          cursor: pointer;
        }
      }
    }
    .btns {
      flex: 1;
      align-self: center;
      display: flex;
      justify-content: flex-start;
      .btn-item {
        cursor: pointer;
        width: 96px;
        height: 36px;
        text-align: center;
        font-size: 14px;
        line-height: 36px;
      }
      .to-upload {
        background-color: #fff;
        margin-left: 23px;
        margin-right: 30px;
        box-shadow: 0px 0px 4px 0px rgba(194, 194, 194, 0.5);
        border-radius: 2px;
        border: 1px solid #cad6ee;
      }
      .confirm {
        color: #fff;
        background: #096dd9;
        box-shadow: 0px 6px 14px 0px #acc3ee;
        border-radius: 2px;
      }
    }
  }
}
</style>
